/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/



const PRNEING = 'pending';
const FULFILLED =  'fulfilled';
const REJECTED = 'rejected';



class myPromise {
    // 传入执行器，立即执行
    constructor (executor) {
        try {
            executor(this.resolve,this.reject);
        } catch (e) {
            this.reject(e);
        }
    }

    status = PRNEING;   // 状态判定
    value = undefined;   //成功的值
    reason = undefined;     // 失败的原因
    // successCallback = undefined;    // 成功的回调
    // failCallback = undefined;    // 失败的的回调

    // then方法多次调用且异步
    successCallback = [];    // 成功的回调
    failCallback = [];    // 失败的的回调
   
    resolve = value => {    // 成功的状态
        // 如果状态不是等待，组织继续执行
        if (this.status !== PRNEING)  return;
        this.status = FULFILLED;
        // 记录成功的值
        this.value = value;
        // 执行成功的回调
        // this.successCallback && this.successCallback(this.value);
        while (this.successCallback.length) {
            this.successCallback.shift()();
        }
        

    }

    reject = reason => {    // 失败的状态
        if (this.status !== PRNEING)  return;
        this.status = REJECTED;
        // 记录失败的原因
        this.reason = reason;
        // 执行失败的回调
        // this.failCallback && this.failCallback(this.reason);
        while (this.failCallback.length) {
            this.failCallback.shift()();
        }
    }

    then (successCallback,failCallback) {

        // 参数可选
        successCallback = successCallback ? successCallback : value => value;
        failCallback = failCallback ? failCallback: reason => { throw reason };


        // 返回promise对象，才可以继续链式调用then
        // promise2在promise执行后才会获取到，此时要等待promise执行完成，加异步
        let promise2 = new myPromise( (resolve,reject) => {
            // 判断状态
            if (this.status === FULFILLED) {
                setTimeout(() => {
                    try {
                        // 将x的值作为参数，给下一个then
                        // x 如果是自己返回的promise对象，会造成自身的循环，此时直接reject
                        let x = successCallback(this.value);

                        // 传递参数 ？
                        // 普通值，直接resolve
                        // promise对象，要根据对应的状态改变去回调对应的函数
                        resolvePromise(promise2,x,resolve,reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            }else if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        let x = failCallback(this.reason);
                        resolvePromise(promise2,x,resolve,reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
                
            }else{
                // 在主线程有异步时，要保证后续异步的顺利执行
                // 回调函数要保存
                // this.successCallback = successCallback;
                // this.failCallback = failCallback;
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let x = successCallback(this.value);
                            resolvePromise(promise2,x,resolve,reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0);
                });
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let x = failCallback(this.reason);
                            resolvePromise(promise2,x,resolve,reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0);
                });

            }
        })

        return promise2;
        
    }

    finally (callback) {    
        // 得到promise的状态
        return this.then(
            // 全部转换成promise对象返回
            value => {
                return myPromise.resolve(callback()).then(() => value);
            }, 
            reason => {
              return myPromise.resolve(callback()).then(() => { throw reason })
            }
        )
    }

    catch (failCallback) {
        return this.then(undefined, failCallback)
    }
     
    static all (array) {
        // 循环数组，如果是普通值，直接放到结果数组等待所有执行
        // promise对象则执行，将结果放到结果数组
        let result = [];    //结果数组
        let index = 0;  //  执行标记--包含异步操作的情况
        return new myPromise( (resolve,reject) => {

            function addData(key,value) {   //将值放到数组中
                result[key] = value;
                index++;
                if (index === array.length) {   //当index====数组长度，说明all方法都已经执行完毕
                    resolve(result);
                }
            }

           for (let i = 0; i < array.length; i++) {
               const current = array[i];
                if (current instanceof myPromise) {
                    current.then(
                        value => addData(i,value),
                        reason => reject(reason)
                    )
                }else{
                    addData(i,array[i])
                }
            }
           
        })
    }

    static resolve (value) {
        // 如果传进的是promise对象，直接返回
        // 如果是普通值变成promise对象返回
        if (value instanceof myPromise) return value;
        return new myPromise(resolve => resolve(value));
      }
   
}
function  resolvePromise (promise2,x,resolve,reject) {
    // 判断否是自身返回的promise对象
    if (x === promise2) {
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
    }

    // 判断x是否是promise对象，是否是myPromise的实例
    if (x instanceof myPromise) {
        // x.then(
        //     value => {
        //         resolve(value);
        //     },
        //     reason => {
        //         reject(reason);
        //     }
        // )
        x.then(resolve,reject);
    }else{
        //普通值
        resolve(x);
    }
}

module.exports = myPromise;